source('../settings/settings.R')
source('commonFunctions.R')
library(nlme)
library(lme4)
set.seed(43)
inputFileDrive1 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=1, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive2 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=2, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive3 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=3, distPrev=DISTANCE_PREV, distNext=DISTANCE_NEXT))
inputFileDrive4 <- str_interp("../data/processed/analysis/TT1_Drive_${drive}_PP_${distPrev}m_${distNext}m.csv", list(drive=4, distPrev=30, distNext=30))
drive1 <- read.csv(inputFileDrive1)
drive2 <- read.csv(inputFileDrive2)
drive3 <- read.csv(inputFileDrive3)
drive4 <- read.csv(inputFileDrive4, stringsAsFactors = T)
dfSeg <- data.frame(rep(1, nrow(drive4)), rep(2, nrow(drive4)), rep(3, nrow(drive4)), rep(4, nrow(drive4)))
names(dfSeg) <- c("Seg1", "Seg2", "Seg3", "Seg4")
combinedDf_Seg1 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg1, drive3$MeanPP_Seg1,
drive2$MeanPP_Seg0_1, drive3$MeanPP_Seg0_1,
drive2$StdPP_Seg1, drive3$StdPP_Seg1,
drive2$StdPP_Seg0_1, drive3$StdPP_Seg0_1,
drive2$MeanPP_AccHigh1, drive3$MeanPP_AccHigh1,
drive2$X.MeanPP_AccLow1, drive3$X.MeanPP_AccLow1,
drive2$StdPP_AccHigh1, drive3$StdPP_AccHigh1,
drive2$StdPP_AccLow1, drive3$StdPP_AccLow1,
dfSeg$Seg1
)
combinedDf_Seg2 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg2, drive3$MeanPP_Seg2,
drive2$MeanPP_Seg0_2, drive3$MeanPP_Seg0_2,
drive2$StdPP_Seg2, drive3$StdPP_Seg2,
drive2$StdPP_Seg0_2, drive3$StdPP_Seg0_2,
drive2$MeanPP_AccHigh2, drive3$MeanPP_AccHigh2,
drive2$X.MeanPP_AccLow2, drive3$X.MeanPP_AccLow2,
drive2$StdPP_AccHigh2, drive3$StdPP_AccHigh2,
drive2$StdPP_AccLow2, drive3$StdPP_AccLow2,
dfSeg$Seg2
)
combinedDf_Seg3 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg3, drive3$MeanPP_Seg3,
drive2$MeanPP_Seg0_3, drive3$MeanPP_Seg0_3,
drive2$StdPP_Seg3, drive3$StdPP_Seg3,
drive2$StdPP_Seg0_3, drive3$StdPP_Seg0_3,
drive2$MeanPP_AccHigh3, drive3$MeanPP_AccHigh3,
drive2$X.MeanPP_AccLow3, drive3$X.MeanPP_AccLow3,
drive2$StdPP_AccHigh3, drive3$StdPP_AccHigh3,
drive2$StdPP_AccLow3, drive3$StdPP_AccLow3,
dfSeg$Seg3
)
combinedDf_Seg4 <- cbind(drive4,
drive1$MeanPP_Seg0,
drive2$MeanPP_Seg4, drive3$MeanPP_Seg4,
drive2$MeanPP_Seg0_4, drive3$MeanPP_Seg0_4,
drive2$StdPP_Seg4, drive3$StdPP_Seg4,
drive2$StdPP_Seg0_4, drive3$StdPP_Seg0_4,
drive2$MeanPP_AccHigh4, drive3$MeanPP_AccHigh4,
drive2$X.MeanPP_AccLow4, drive3$X.MeanPP_AccLow4,
drive2$StdPP_AccHigh4, drive3$StdPP_AccHigh4,
drive2$StdPP_AccLow4, drive3$StdPP_AccLow4,
dfSeg$Seg4
)
common_names <- c("PP_Dev_1_Turning",
"PP_Dev_2_Straight", "PP_Dev_3_Straight",
"PP_Dev_2_Turning", "PP_Dev_3_Turning",
"Std_PP_2_Straight", "Std_PP_3_Straight",
"Std_PP_2_Turning", "Std_PP_3_Turning",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow",
"Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
"Std_PP_2_AccLow", "Std_PP_3_AccLow",
"Segment")
names(combinedDf_Seg1) <- c(names(drive4), common_names)
names(combinedDf_Seg2) <- c(names(drive4), common_names)
names(combinedDf_Seg3) <- c(names(drive4), common_names)
names(combinedDf_Seg4) <- c(names(drive4), common_names)
# combinedDf_Seg1$Subject <- paste0(as.factor(combinedDf_Seg1$Subject), ".S1")
# combinedDf_Seg2$Subject <- paste0(as.factor(combinedDf_Seg2$Subject), ".S2")
# combinedDf_Seg3$Subject <- paste0(as.factor(combinedDf_Seg3$Subject), ".S3")
# combinedDf_Seg4$Subject <- paste0(as.factor(combinedDf_Seg4$Subject), ".S4")
combinedDf <- rbind(combinedDf_Seg1, combinedDf_Seg2, combinedDf_Seg3, combinedDf_Seg4)
# combinedDf$Subject <- paste0("#", str_pad(combinedDf$Subject, 2, pad="0"))
combinedDf$Segment <- as.factor(combinedDf$Segment)
combinedDf$ActivityEncoded <- factor(ifelse(combinedDf$Activity == "NO", "1", ifelse(combinedDf$Activity == "C", "2", "3")))
combinedDf <- combinedDf[complete.cases(combinedDf),]
combinedDf$Subject = as.factor(combinedDf$Subject)
model = lm(PP_After ~
PP_Dev_2_Straight +
PP_Dev_3_Straight +
PP_Dev_2_Turning +
PP_Dev_3_Turning +
Std_PP_2_Straight +
Std_PP_3_Straight +
Std_PP_2_Turning +
Std_PP_3_Turning +
# PP_Prior +
factor(ActivityEncoded),
data=combinedDf, random = ~1|factor(Subject), method = "REML")
method = 'REML' is not supported. Using 'qr'In lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
extra argument ‘random’ will be disregarded
# anova(model)
summary(model)
Call:
lm(formula = PP_After ~ PP_Dev_2_Straight + PP_Dev_3_Straight +
PP_Dev_2_Turning + PP_Dev_3_Turning + Std_PP_2_Straight +
Std_PP_3_Straight + Std_PP_2_Turning + Std_PP_3_Turning +
factor(ActivityEncoded), data = combinedDf, method = "REML",
random = ~1 | factor(Subject))
Residuals:
Min 1Q Median 3Q Max
-0.17764 -0.07137 0.00092 0.05144 0.34502
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.02294 0.04870 -0.471 0.6393
PP_Dev_2_Straight 0.68712 0.15583 4.410 4.45e-05 ***
PP_Dev_3_Straight -0.37734 0.23618 -1.598 0.1155
PP_Dev_2_Turning -0.22015 0.14683 -1.499 0.1391
PP_Dev_3_Turning 0.38632 0.22101 1.748 0.0857 .
Std_PP_2_Straight 0.02144 0.38757 0.055 0.9561
Std_PP_3_Straight 0.50369 0.36818 1.368 0.1765
Std_PP_2_Turning -0.08343 0.50205 -0.166 0.8686
Std_PP_3_Turning -0.95800 0.60836 -1.575 0.1207
factor(ActivityEncoded)2 0.08647 0.03285 2.633 0.0108 *
factor(ActivityEncoded)3 0.17032 0.03184 5.349 1.51e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.0993 on 59 degrees of freedom
Multiple R-squared: 0.5613, Adjusted R-squared: 0.4869
F-statistic: 7.548 on 10 and 59 DF, p-value: 1.338e-07
plot(model)




No Random Effects
linearModel1 <- lm(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf)
# anova(model)
summary(linearModel1)
Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh +
Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow + factor(ActivityEncoded),
data = combinedDf)
Residuals:
Min 1Q Median 3Q Max
-0.143483 -0.066038 -0.007552 0.051595 0.300313
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.06552 0.03640 -1.800 0.07695 .
Mean_PP_2_AccHigh 1.63376 0.50590 3.229 0.00203 **
Mean_PP_2_AccLow -1.15253 0.49763 -2.316 0.02405 *
Mean_PP_3_AccHigh 0.74436 0.31520 2.362 0.02152 *
Mean_PP_3_AccLow -0.66142 0.33913 -1.950 0.05589 .
Std_PP_2_AccHigh -1.28974 1.45755 -0.885 0.37982
Std_PP_2_AccLow 0.79583 1.15728 0.688 0.49435
Std_PP_3_AccHigh 0.15278 0.94374 0.162 0.87195
Std_PP_3_AccLow 0.91693 0.83810 1.094 0.27838
factor(ActivityEncoded)2 0.08724 0.03041 2.869 0.00571 **
factor(ActivityEncoded)3 0.14810 0.03043 4.867 8.83e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.09353 on 59 degrees of freedom
Multiple R-squared: 0.6108, Adjusted R-squared: 0.5448
F-statistic: 9.259 on 10 and 59 DF, p-value: 5.37e-09
plot(linearModel1)




With Random Effects
linearModel1 <- lmer(PP_After ~
(1 | Subject)
+ Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
+ Std_PP_2_AccHigh
+ Std_PP_2_AccLow
+ Std_PP_3_AccHigh
+ Std_PP_3_AccLow,
# + factor(ActivityEncoded),
data=combinedDf, REML = T)
Model failed to converge with max|grad| = 0.0670118 (tol = 0.002, component 1)Model is nearly unidentifiable: very large eigenvalue
- Rescale variables?Model may not have converged with 1 eigenvalue close to zero: 1.1e-10
# anova(model)
summary(linearModel1)
Linear mixed model fit by REML. t-tests use Satterthwaite's method ['lmerModLmerTest']
Formula: PP_After ~ (1 | Subject) + Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + Std_PP_2_AccHigh + Std_PP_2_AccLow + Std_PP_3_AccHigh + Std_PP_3_AccLow
Data: combinedDf
REML criterion at convergence: -1503.4
Scaled residuals:
Min 1Q Median 3Q Max
-4.063e-07 -1.190e-07 -6.100e-09 1.335e-07 6.294e-07
Random effects:
Groups Name Variance Std.Dev.
Subject (Intercept) 7.124e-03 8.440e-02
Residual 2.068e-17 4.548e-09
Number of obs: 70, groups: Subject, 21
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 8.333e-02 2.203e-02 7.891e-05 3.783 0.999
Mean_PP_2_AccHigh 6.340e-14 5.153e-08 7.891e-05 0.000 1.000
Mean_PP_2_AccLow -3.925e-14 3.923e-08 7.891e-05 0.000 1.000
Mean_PP_3_AccHigh -1.859e-15 1.820e-08 7.891e-05 0.000 1.000
Mean_PP_3_AccLow 6.079e-15 2.337e-08 7.891e-05 0.000 1.000
Std_PP_2_AccHigh 1.459e-14 8.442e-08 7.891e-05 0.000 1.000
Std_PP_2_AccLow 1.525e-16 6.425e-08 7.891e-05 0.000 1.000
Std_PP_3_AccHigh -2.153e-14 5.689e-08 7.891e-05 0.000 1.000
Std_PP_3_AccLow 2.408e-14 4.744e-08 7.891e-05 0.000 1.000
Correlation of Fixed Effects:
(Intr) M_PP_2_AH M_PP_2_AL M_PP_3_AH M_PP_3_AL S_PP_2_AH S_PP_2_AL S_PP_3_AH
Mn_PP_2_AcH 0.000
Mn_PP_2_AcL 0.000 -0.960
Mn_PP_3_AcH 0.000 0.005 -0.029
Mn_PP_3_AcL 0.000 -0.055 0.015 -0.697
Std_PP_2_AH 0.000 0.147 -0.186 0.088 -0.073
Std_PP_2_AL 0.000 0.030 -0.013 -0.131 0.089 -0.877
Std_PP_3_AH 0.000 0.063 -0.115 -0.453 0.312 -0.339 0.190
Std_PP_3_AL 0.000 0.205 -0.222 0.376 -0.327 0.307 -0.236 -0.528
convergence code: 0
Model failed to converge with max|grad| = 0.0670118 (tol = 0.002, component 1)
Model is nearly unidentifiable: very large eigenvalue
- Rescale variables?
plot(linearModel1)

linearModel1 <- lm(PP_After ~
Mean_PP_2_AccHigh
+ Mean_PP_2_AccLow
+ Mean_PP_3_AccHigh
+ Mean_PP_3_AccLow
# + PP_Prior
+ factor(ActivityEncoded),
data=combinedDf)
# anova(model)
summary(linearModel1)
Call:
lm(formula = PP_After ~ Mean_PP_2_AccHigh + Mean_PP_2_AccLow +
Mean_PP_3_AccHigh + Mean_PP_3_AccLow + factor(ActivityEncoded),
data = combinedDf)
Residuals:
Min 1Q Median 3Q Max
-0.14161 -0.06916 -0.00742 0.04809 0.30760
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.05248 0.02751 -1.907 0.06103 .
Mean_PP_2_AccHigh 1.64939 0.38841 4.246 7.28e-05 ***
Mean_PP_2_AccLow -1.14578 0.37518 -3.054 0.00331 **
Mean_PP_3_AccHigh 0.65161 0.26162 2.491 0.01540 *
Mean_PP_3_AccLow -0.60534 0.28421 -2.130 0.03709 *
factor(ActivityEncoded)2 0.08906 0.02976 2.993 0.00394 **
factor(ActivityEncoded)3 0.15955 0.02892 5.516 6.92e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.09303 on 63 degrees of freedom
Multiple R-squared: 0.5888, Adjusted R-squared: 0.5496
F-statistic: 15.03 on 6 and 63 DF, p-value: 1.372e-10
plot(linearModel1)




Machine Learning
ppAfter <- combinedDf$PP_After
ppAfterArray <- matrix(ppAfter, nrow = 1,ncol = length(ppAfter))
thresholdPPAfter <- otsu(ppAfterArray, range=c(min(ppAfter), max(ppAfter))) # Expected Threshold > 0.10123
print(paste0('Threshold: ', thresholdPPAfter))
[1] "Threshold: 0.101235546875"
selectedDf <- combinedDf %>% select(
"Subject", "Activity", "PP_After", # "PP_Prior",
"Mean_PP_2_AccHigh", "Mean_PP_3_AccHigh",
"Mean_PP_2_AccLow", "Mean_PP_3_AccLow"
# "Std_PP_2_AccHigh", "Std_PP_3_AccHigh",
# "Std_PP_2_AccLow", "Std_PP_3_AccLow"
)
selectedDf$Subject <- NULL
selectedDf$Activity_NO <- ifelse(selectedDf$Activity == "NO", 1, 0)
selectedDf$Activity_C <- ifelse(selectedDf$Activity == "C", 1, 0)
selectedDf$Activity_M <- ifelse(selectedDf$Activity == "M", 1, 0)
selectedDf$Activity <- NULL
# selectedDf$PP_Dev_1_Turning <- NULL
# selectedDf$Std_PP_2_Straight <- NULL
# selectedDf$Std_PP_2_Turning <- NULL
# selectedDf$Std_PP_3_Straight <- NULL
# selectedDf$Std_PP_3_Turning <- NULL
#
# # According to Linear model
# selectedDf$PP_Dev_2_Straight <- abs(selectedDf$PP_Dev_2_Straight)
# selectedDf$PP_Dev_3_Straight <- abs(selectedDf$PP_Dev_3_Straight)
# selectedDf$PP_Dev_2_Turning <- abs(selectedDf$PP_Dev_2_Turning)
# selectedDf$PP_Dev_3_Turning <- abs(selectedDf$PP_Dev_3_Turning)
# selectedDf$PP_Prior <- abs(selectedDf$PP_Prior) # NULL
selectedDf$Class <- ifelse(selectedDf$PP_After >= thresholdPPAfter, T, F)
selectedDf$PP_After <- NULL
print(names(selectedDf))
[1] "Mean_PP_2_AccHigh" "Mean_PP_3_AccHigh" "Mean_PP_2_AccLow" "Mean_PP_3_AccLow" "Activity_NO" "Activity_C"
[7] "Activity_M" "Class"
# library(mefa)
# combinedDf <- rep(combinedDf, 10)
set.seed(39)
n_folds <- 10
params <- param <- list(objective = "binary:logistic",
booster = "gbtree",
eval_metric = "auc",
eta = 0.1,
max_depth = 10,
alpha = 1,
lambda = 0,
gamma = 0.45,
min_child_weight = 0.3,
subsample = 1,
colsample_bytree = 1)
# XGBoost Model
xgb_m <- xgb.cv( params = param,
data = as.matrix(selectedDf %>% select(-Class)) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 1)
# xgb_m$evaluation_log[xgb_m$best_iteration,"test_auc_mean"]
xgb_m$evaluation_log[xgb_m$best_iteration,]
NA
Performance Metrics
# Prediction
selectedDf$clsPred <- round(xgb_m$pred)
computePerformanceResults <- function(sdat){
sdat = sdat[complete.cases(sdat),]
acc = sum(sdat[,1] == sdat[,2])/nrow(sdat)
conf_mat = table(sdat)
specif = conf_mat[1,1]/sum(conf_mat[,1])
sensiv = conf_mat[2,2]/sum(conf_mat[,2])
preci = conf_mat[2,2]/sum(conf_mat[2,])
npv = conf_mat[1,1]/sum(conf_mat[1,])
return(c(acc,specif,sensiv,preci,npv))
}
# Get average performance
performance <- computePerformanceResults(selectedDf %>% select(Class, clsPred))
acc <- performance[1]
prec <- performance[4]
recall <- performance[3]
spec <- performance[2]
npv <- performance[5]
f1 <- (2 * recall * prec) / (recall + prec)
auc <- as.numeric(xgb_m$evaluation_log[xgb_m$best_iteration, "test_auc_mean"])
print(paste("Accuracy=", round(acc, 2)))
[1] "Accuracy= 0.89"
print(paste("Precision=", round(prec, 2)))
[1] "Precision= 0.8"
print(paste("Recall=", round(recall, 2)))
[1] "Recall= 0.92"
print(paste("Specificity=", round(spec, 2)))
[1] "Specificity= 0.86"
print(paste("NPV=", round(npv, 2)))
[1] "NPV= 0.95"
print(paste("F1=", round(f1, 2)))
[1] "F1= 0.86"
print(paste("AUC=", round(auc, 2)))
[1] "AUC= 0.93"
# Importance
bst <- xgboost( params = param,
data = as.matrix(selectedDf %>% select(-c(Class, clsPred))) ,
label = selectedDf$Class,
nrounds = 100,
verbose = F,
prediction = T,
maximize = F, # Change this value to F will help to run with more itineration
nfold = n_folds,
metrics = c("auc", "error"),
early_stopping_rounds = 50,
stratified = T,
scale_pos_weight = 1)
importanceDf <- xgb.importance(colnames(selectedDf %>% select(-c(Class, clsPred))), model = bst)
print(importanceDf)
library(pROC)
dfROC <- pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<")
# it = which.max(xgb_m$evaluation_log$test_auc_mean)
# best.iter = xgb_m$evaluation_log$iter[it]
# best.iter
plot(pROC::roc(response = ifelse(selectedDf$Class==T, 1, 0),
predictor = round(xgb_m$pred),
levels=c(0, 1), direction = "<"),
legacy.axes = TRUE,
main="ROC Curve",
lwd=1.5)

Plot feature importance
yAxis <- list(
title = 'Importance',
range=c(0.0, 1.0)
)
xAxis <- list(
title = ''
)
importanceDf$Feature <- factor(importanceDf$Feature, levels = importanceDf[order(-Gain),]$Feature)
fig_Importance <- plot_ly(importanceDf, x = ~Feature, y = ~Gain, type = 'bar', name = 'Gain', width=600) %>%
add_trace(y = ~Cover, name = 'Cover') %>%
add_trace(y = ~Frequency, name = 'Frequency') %>%
layout(yaxis = yAxis, xaxis=xAxis, barmode = 'group', title="Feature Importance") %>%
config(.Last.value, mathjax = 'cdn')
htmltools::tagList(fig_Importance)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnNvdXJjZSgnLi4vc2V0dGluZ3Mvc2V0dGluZ3MuUicpCnNvdXJjZSgnY29tbW9uRnVuY3Rpb25zLlInKQpsaWJyYXJ5KG5sbWUpCmxpYnJhcnkobG1lNCkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoNDMpCmlucHV0RmlsZURyaXZlMSA8LSBzdHJfaW50ZXJwKCIuLi9kYXRhL3Byb2Nlc3NlZC9hbmFseXNpcy9UVDFfRHJpdmVfJHtkcml2ZX1fUFBfJHtkaXN0UHJldn1tXyR7ZGlzdE5leHR9bS5jc3YiLCBsaXN0KGRyaXZlPTEsIGRpc3RQcmV2PURJU1RBTkNFX1BSRVYsIGRpc3ROZXh0PURJU1RBTkNFX05FWFQpKQppbnB1dEZpbGVEcml2ZTIgPC0gc3RyX2ludGVycCgiLi4vZGF0YS9wcm9jZXNzZWQvYW5hbHlzaXMvVFQxX0RyaXZlXyR7ZHJpdmV9X1BQXyR7ZGlzdFByZXZ9bV8ke2Rpc3ROZXh0fW0uY3N2IiwgbGlzdChkcml2ZT0yLCBkaXN0UHJldj1ESVNUQU5DRV9QUkVWLCBkaXN0TmV4dD1ESVNUQU5DRV9ORVhUKSkKaW5wdXRGaWxlRHJpdmUzIDwtIHN0cl9pbnRlcnAoIi4uL2RhdGEvcHJvY2Vzc2VkL2FuYWx5c2lzL1RUMV9Ecml2ZV8ke2RyaXZlfV9QUF8ke2Rpc3RQcmV2fW1fJHtkaXN0TmV4dH1tLmNzdiIsIGxpc3QoZHJpdmU9MywgZGlzdFByZXY9RElTVEFOQ0VfUFJFViwgZGlzdE5leHQ9RElTVEFOQ0VfTkVYVCkpCmlucHV0RmlsZURyaXZlNCA8LSBzdHJfaW50ZXJwKCIuLi9kYXRhL3Byb2Nlc3NlZC9hbmFseXNpcy9UVDFfRHJpdmVfJHtkcml2ZX1fUFBfJHtkaXN0UHJldn1tXyR7ZGlzdE5leHR9bS5jc3YiLCBsaXN0KGRyaXZlPTQsIGRpc3RQcmV2PTMwLCBkaXN0TmV4dD0zMCkpCgpkcml2ZTEgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUxKQpkcml2ZTIgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUyKQpkcml2ZTMgPC0gcmVhZC5jc3YoaW5wdXRGaWxlRHJpdmUzKQoKZHJpdmU0IDwtIHJlYWQuY3N2KGlucHV0RmlsZURyaXZlNCwgc3RyaW5nc0FzRmFjdG9ycyA9IFQpCmBgYAoKYGBge3J9CmRmU2VnIDwtIGRhdGEuZnJhbWUocmVwKDEsIG5yb3coZHJpdmU0KSksIHJlcCgyLCBucm93KGRyaXZlNCkpLCByZXAoMywgbnJvdyhkcml2ZTQpKSwgcmVwKDQsIG5yb3coZHJpdmU0KSkpCm5hbWVzKGRmU2VnKSA8LSBjKCJTZWcxIiwgIlNlZzIiLCAiU2VnMyIsICJTZWc0IikKCmNvbWJpbmVkRGZfU2VnMSA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcxLCBkcml2ZTMkTWVhblBQX1NlZzEsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8xLCBkcml2ZTMkTWVhblBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMSwgZHJpdmUzJFN0ZFBQX1NlZzEsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMSwgZHJpdmUzJFN0ZFBQX1NlZzBfMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gxLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gxLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cxLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDEsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMSwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MSwgZHJpdmUzJFN0ZFBQX0FjY0xvdzEsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMQogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMiA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWcyLCBkcml2ZTMkTWVhblBQX1NlZzIsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8yLCBkcml2ZTMkTWVhblBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMiwgZHJpdmUzJFN0ZFBQX1NlZzIsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMiwgZHJpdmUzJFN0ZFBQX1NlZzBfMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gyLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gyLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3cyLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDIsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMiwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MiwgZHJpdmUzJFN0ZFBQX0FjY0xvdzIsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMgogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnMyA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWczLCBkcml2ZTMkTWVhblBQX1NlZzMsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF8zLCBkcml2ZTMkTWVhblBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnMywgZHJpdmUzJFN0ZFBQX1NlZzMsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfMywgZHJpdmUzJFN0ZFBQX1NlZzBfMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2gzLCBkcml2ZTMkTWVhblBQX0FjY0hpZ2gzLAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3czLCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93MywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDMsIGRyaXZlMyRTdGRQUF9BY2NIaWdoMywKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93MywgZHJpdmUzJFN0ZFBQX0FjY0xvdzMsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnMwogICAgICAgICAgICAgICAgICApCmNvbWJpbmVkRGZfU2VnNCA8LSBjYmluZChkcml2ZTQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMSRNZWFuUFBfU2VnMCwgCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJE1lYW5QUF9TZWc0LCBkcml2ZTMkTWVhblBQX1NlZzQsIAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRNZWFuUFBfU2VnMF80LCBkcml2ZTMkTWVhblBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfU2VnNCwgZHJpdmUzJFN0ZFBQX1NlZzQsCiAgICAgICAgICAgICAgICAgICAgZHJpdmUyJFN0ZFBQX1NlZzBfNCwgZHJpdmUzJFN0ZFBQX1NlZzBfNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkTWVhblBQX0FjY0hpZ2g0LCBkcml2ZTMkTWVhblBQX0FjY0hpZ2g0LAogICAgICAgICAgICAgICAgICAgIGRyaXZlMiRYLk1lYW5QUF9BY2NMb3c0LCBkcml2ZTMkWC5NZWFuUFBfQWNjTG93NCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjSGlnaDQsIGRyaXZlMyRTdGRQUF9BY2NIaWdoNCwKICAgICAgICAgICAgICAgICAgICBkcml2ZTIkU3RkUFBfQWNjTG93NCwgZHJpdmUzJFN0ZFBQX0FjY0xvdzQsCiAgICAgICAgICAgICAgICAgICAgZGZTZWckU2VnNAogICAgICAgICAgICAgICAgICApCgpjb21tb25fbmFtZXMgPC0gYygiUFBfRGV2XzFfVHVybmluZyIsCiAgICAgICAgICAgICAgICAgICJQUF9EZXZfMl9TdHJhaWdodCIsICJQUF9EZXZfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiUFBfRGV2XzJfVHVybmluZyIsICJQUF9EZXZfM19UdXJuaW5nIiwgCiAgICAgICAgICAgICAgICAgICJTdGRfUFBfMl9TdHJhaWdodCIsICJTdGRfUFBfM19TdHJhaWdodCIsIAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfVHVybmluZyIsICJTdGRfUFBfM19UdXJuaW5nIiwKICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjSGlnaCIsICJNZWFuX1BQXzNfQWNjSGlnaCIsCiAgICAgICAgICAgICAgICAgICJNZWFuX1BQXzJfQWNjTG93IiwgIk1lYW5fUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAiU3RkX1BQXzJfQWNjSGlnaCIsICJTdGRfUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIlN0ZF9QUF8yX0FjY0xvdyIsICJTdGRfUFBfM19BY2NMb3ciLAogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgIlNlZ21lbnQiKQoKbmFtZXMoY29tYmluZWREZl9TZWcxKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWcyKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWczKSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKbmFtZXMoY29tYmluZWREZl9TZWc0KSA8LSBjKG5hbWVzKGRyaXZlNCksIGNvbW1vbl9uYW1lcykKCiMgY29tYmluZWREZl9TZWcxJFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzEkU3ViamVjdCksICIuUzEiKQojIGNvbWJpbmVkRGZfU2VnMiRTdWJqZWN0IDwtIHBhc3RlMChhcy5mYWN0b3IoY29tYmluZWREZl9TZWcyJFN1YmplY3QpLCAiLlMyIikKIyBjb21iaW5lZERmX1NlZzMkU3ViamVjdCA8LSBwYXN0ZTAoYXMuZmFjdG9yKGNvbWJpbmVkRGZfU2VnMyRTdWJqZWN0KSwgIi5TMyIpCiMgY29tYmluZWREZl9TZWc0JFN1YmplY3QgPC0gcGFzdGUwKGFzLmZhY3Rvcihjb21iaW5lZERmX1NlZzQkU3ViamVjdCksICIuUzQiKQoKY29tYmluZWREZiA8LSByYmluZChjb21iaW5lZERmX1NlZzEsIGNvbWJpbmVkRGZfU2VnMiwgY29tYmluZWREZl9TZWczLCBjb21iaW5lZERmX1NlZzQpCgojIGNvbWJpbmVkRGYkU3ViamVjdCA8LSBwYXN0ZTAoIiMiLCBzdHJfcGFkKGNvbWJpbmVkRGYkU3ViamVjdCwgMiwgcGFkPSIwIikpCmNvbWJpbmVkRGYkU2VnbWVudCA8LSBhcy5mYWN0b3IoY29tYmluZWREZiRTZWdtZW50KQpjb21iaW5lZERmJEFjdGl2aXR5RW5jb2RlZCA8LSBmYWN0b3IoaWZlbHNlKGNvbWJpbmVkRGYkQWN0aXZpdHkgPT0gIk5PIiwgIjEiLCBpZmVsc2UoY29tYmluZWREZiRBY3Rpdml0eSA9PSAiQyIsICIyIiwgIjMiKSkpCgpjb21iaW5lZERmIDwtIGNvbWJpbmVkRGZbY29tcGxldGUuY2FzZXMoY29tYmluZWREZiksXQpjb21iaW5lZERmJFN1YmplY3QgPSBhcy5mYWN0b3IoY29tYmluZWREZiRTdWJqZWN0KQpgYGAKCgpgYGB7cn0KbW9kZWwgPSBsbShQUF9BZnRlciB+IAogICAgICAgICAgICAgIFBQX0Rldl8yX1N0cmFpZ2h0ICsgCiAgICAgICAgICAgICAgUFBfRGV2XzNfU3RyYWlnaHQgKwogICAgICAgICAgICAgIFBQX0Rldl8yX1R1cm5pbmcgKyAKICAgICAgICAgICAgICBQUF9EZXZfM19UdXJuaW5nICsgCiAgICAgICAgICAgICAgU3RkX1BQXzJfU3RyYWlnaHQgKyAKICAgICAgICAgICAgICBTdGRfUFBfM19TdHJhaWdodCArIAogICAgICAgICAgICAgIFN0ZF9QUF8yX1R1cm5pbmcgKwogICAgICAgICAgICAgIFN0ZF9QUF8zX1R1cm5pbmcgKwogICAgICAgICAgICAgICMgUFBfUHJpb3IgKwogICAgICAgICAgICAgIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIHJhbmRvbSA9IH4xfGZhY3RvcihTdWJqZWN0KSwgbWV0aG9kID0gIlJFTUwiKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKcGxvdChtb2RlbCkKYGBgCgojIE5vIFJhbmRvbSBFZmZlY3RzCmBgYHtyfQpsaW5lYXJNb2RlbDEgPC0gbG0oUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYpCgojIGFub3ZhKG1vZGVsKQpzdW1tYXJ5KGxpbmVhck1vZGVsMSkKcGxvdChsaW5lYXJNb2RlbDEpCmBgYAoKCiMgV2l0aCBSYW5kb20gRWZmZWN0cwpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtZXIoUFBfQWZ0ZXIgfiAKICAgICAgICAgICAgICAgICgxIHwgU3ViamVjdCkKICAgICAgICAgICAgICArIE1lYW5fUFBfMl9BY2NIaWdoCiAgICAgICAgICAgICAgKyBNZWFuX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBNZWFuX1BQXzNfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0xvdwogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgU3RkX1BQXzJfQWNjTG93CiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NIaWdoCiAgICAgICAgICAgICAgKyBTdGRfUFBfM19BY2NMb3csCiAgICAgICAgICAgICAgIyArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLAogICAgICAgICAgICBkYXRhPWNvbWJpbmVkRGYsIFJFTUwgPSBUKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCgpgYGB7cn0KbGluZWFyTW9kZWwxIDwtIGxtKFBQX0FmdGVyIH4gCiAgICAgICAgICAgICAgICBNZWFuX1BQXzJfQWNjSGlnaAogICAgICAgICAgICAgICsgTWVhbl9QUF8yX0FjY0xvdwogICAgICAgICAgICAgICsgTWVhbl9QUF8zX0FjY0hpZ2gKICAgICAgICAgICAgICArIE1lYW5fUFBfM19BY2NMb3cKICAgICAgICAgICAgICAjICsgUFBfUHJpb3IKICAgICAgICAgICAgICArIGZhY3RvcihBY3Rpdml0eUVuY29kZWQpLCAKICAgICAgICAgICAgZGF0YT1jb21iaW5lZERmKQoKIyBhbm92YShtb2RlbCkKc3VtbWFyeShsaW5lYXJNb2RlbDEpCnBsb3QobGluZWFyTW9kZWwxKQpgYGAKCiMjIE1hY2hpbmUgTGVhcm5pbmcKCmBgYHtyfQpwcEFmdGVyIDwtIGNvbWJpbmVkRGYkUFBfQWZ0ZXIKcHBBZnRlckFycmF5IDwtIG1hdHJpeChwcEFmdGVyLCBucm93ID0gMSxuY29sID0gbGVuZ3RoKHBwQWZ0ZXIpKQogIAp0aHJlc2hvbGRQUEFmdGVyIDwtIG90c3UocHBBZnRlckFycmF5LCByYW5nZT1jKG1pbihwcEFmdGVyKSwgbWF4KHBwQWZ0ZXIpKSkgIyBFeHBlY3RlZCBUaHJlc2hvbGQgPiAwLjEwMTIzCnByaW50KHBhc3RlMCgnVGhyZXNob2xkOiAnLCB0aHJlc2hvbGRQUEFmdGVyKSkKCnNlbGVjdGVkRGYgPC0gY29tYmluZWREZiAlPiUgc2VsZWN0KAogICAgICAgICAgICAgICAgICAiU3ViamVjdCIsICJBY3Rpdml0eSIsICJQUF9BZnRlciIsICMgIlBQX1ByaW9yIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NIaWdoIiwgIk1lYW5fUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIk1lYW5fUFBfMl9BY2NMb3ciLCAiTWVhbl9QUF8zX0FjY0xvdyIKICAgICAgICAgICAgICAgICAgIyAiU3RkX1BQXzJfQWNjSGlnaCIsICJTdGRfUFBfM19BY2NIaWdoIiwKICAgICAgICAgICAgICAgICAgIyAiU3RkX1BQXzJfQWNjTG93IiwgIlN0ZF9QUF8zX0FjY0xvdyIKICAgICAgICAgICAgICAgICAgKQoKc2VsZWN0ZWREZiRTdWJqZWN0IDwtIE5VTEwKc2VsZWN0ZWREZiRBY3Rpdml0eV9OTyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRBY3Rpdml0eSA9PSAiTk8iLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5X0MgPC0gaWZlbHNlKHNlbGVjdGVkRGYkQWN0aXZpdHkgPT0gIkMiLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5X00gPC0gaWZlbHNlKHNlbGVjdGVkRGYkQWN0aXZpdHkgPT0gIk0iLCAxLCAwKQpzZWxlY3RlZERmJEFjdGl2aXR5IDwtIE5VTEwKCiMgc2VsZWN0ZWREZiRQUF9EZXZfMV9UdXJuaW5nIDwtIE5VTEwKIyBzZWxlY3RlZERmJFN0ZF9QUF8yX1N0cmFpZ2h0IDwtIE5VTEwKIyBzZWxlY3RlZERmJFN0ZF9QUF8yX1R1cm5pbmcgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzNfU3RyYWlnaHQgPC0gTlVMTAojIHNlbGVjdGVkRGYkU3RkX1BQXzNfVHVybmluZyA8LSBOVUxMCiMgCiMgIyBBY2NvcmRpbmcgdG8gTGluZWFyIG1vZGVsCiMgc2VsZWN0ZWREZiRQUF9EZXZfMl9TdHJhaWdodCA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfMl9TdHJhaWdodCkKIyBzZWxlY3RlZERmJFBQX0Rldl8zX1N0cmFpZ2h0IDwtIGFicyhzZWxlY3RlZERmJFBQX0Rldl8zX1N0cmFpZ2h0KQojIHNlbGVjdGVkRGYkUFBfRGV2XzJfVHVybmluZyA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfMl9UdXJuaW5nKQojIHNlbGVjdGVkRGYkUFBfRGV2XzNfVHVybmluZyA8LSBhYnMoc2VsZWN0ZWREZiRQUF9EZXZfM19UdXJuaW5nKQojIHNlbGVjdGVkRGYkUFBfUHJpb3IgPC0gYWJzKHNlbGVjdGVkRGYkUFBfUHJpb3IpICMgTlVMTAoKc2VsZWN0ZWREZiRDbGFzcyA8LSBpZmVsc2Uoc2VsZWN0ZWREZiRQUF9BZnRlciA+PSB0aHJlc2hvbGRQUEFmdGVyLCBULCBGKQpzZWxlY3RlZERmJFBQX0FmdGVyIDwtIE5VTEwKCnByaW50KG5hbWVzKHNlbGVjdGVkRGYpKQpgYGAKCmBgYHtyfQojIGxpYnJhcnkobWVmYSkKIyBjb21iaW5lZERmIDwtIHJlcChjb21iaW5lZERmLCAxMCkgCmBgYAoKYGBge3J9CnNldC5zZWVkKDM5KQpuX2ZvbGRzIDwtIDEwCnBhcmFtcyA8LSBwYXJhbSA8LSBsaXN0KG9iamVjdGl2ZSAgICAgICA9ICJiaW5hcnk6bG9naXN0aWMiLCAKICAgICAgICAgICAgICAgYm9vc3RlciAgICAgICAgICA9ICJnYnRyZWUiLAogICAgICAgICAgICAgICBldmFsX21ldHJpYyAgICAgID0gImF1YyIsCiAgICAgICAgICAgICAgIGV0YSAgICAgICAgICAgICAgPSAwLjEsCiAgICAgICAgICAgICAgIG1heF9kZXB0aCAgICAgICAgPSAxMCwKICAgICAgICAgICAgICAgYWxwaGEgICAgICAgICAgICA9IDEsCiAgICAgICAgICAgICAgIGxhbWJkYSAgICAgICAgICAgPSAwLAogICAgICAgICAgICAgICBnYW1tYSAgICAgICAgICAgID0gMC40NSwKICAgICAgICAgICAgICAgbWluX2NoaWxkX3dlaWdodCA9IDAuMywKICAgICAgICAgICAgICAgc3Vic2FtcGxlICAgICAgICA9IDEsCiAgICAgICAgICAgICAgIGNvbHNhbXBsZV9ieXRyZWUgPSAxKQogICAgICAgICAgIAojIFhHQm9vc3QgTW9kZWwgICAgICAgICAKeGdiX20gPC0geGdiLmN2KCAgIHBhcmFtcyAgICAgICAgICAgICAgID0gcGFyYW0sCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBhcy5tYXRyaXgoc2VsZWN0ZWREZiAlPiUgc2VsZWN0KC1DbGFzcykpICwKICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgc2VsZWN0ZWREZiRDbGFzcywKICAgICAgICAgICAgICAgICAgbnJvdW5kcyAgICAgICAgICAgICA9IDEwMCwKICAgICAgICAgICAgICAgICAgdmVyYm9zZSAgICAgICAgICAgICA9IEYsCiAgICAgICAgICAgICAgICAgIHByZWRpY3Rpb24gICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBtYXhpbWl6ZSAgICAgICAgICAgID0gRiwgIyBDaGFuZ2UgdGhpcyB2YWx1ZSB0byBGIHdpbGwgaGVscCB0byBydW4gd2l0aCBtb3JlIGl0aW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgIG5mb2xkICAgICAgICAgICAgICAgPSBuX2ZvbGRzLAogICAgICAgICAgICAgICAgICBtZXRyaWNzICAgICAgICAgICAgID0gYygiYXVjIiwgImVycm9yIiksCiAgICAgICAgICAgICAgICAgIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDUwLAogICAgICAgICAgICAgICAgICBzdHJhdGlmaWVkICAgICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBzY2FsZV9wb3Nfd2VpZ2h0ICAgICAgPSAxKQoKIyB4Z2JfbSRldmFsdWF0aW9uX2xvZ1t4Z2JfbSRiZXN0X2l0ZXJhdGlvbiwidGVzdF9hdWNfbWVhbiJdCnhnYl9tJGV2YWx1YXRpb25fbG9nW3hnYl9tJGJlc3RfaXRlcmF0aW9uLF0KCmBgYAoKIyMgUGVyZm9ybWFuY2UgTWV0cmljcwpgYGB7cn0KIyBQcmVkaWN0aW9uCnNlbGVjdGVkRGYkY2xzUHJlZCA8LSByb3VuZCh4Z2JfbSRwcmVkKQoKY29tcHV0ZVBlcmZvcm1hbmNlUmVzdWx0cyA8LSBmdW5jdGlvbihzZGF0KXsKICBzZGF0ID0gc2RhdFtjb21wbGV0ZS5jYXNlcyhzZGF0KSxdCiAgYWNjID0gc3VtKHNkYXRbLDFdID09IHNkYXRbLDJdKS9ucm93KHNkYXQpCiAgY29uZl9tYXQgPSB0YWJsZShzZGF0KQogIHNwZWNpZiA9IGNvbmZfbWF0WzEsMV0vc3VtKGNvbmZfbWF0WywxXSkKICBzZW5zaXYgPSBjb25mX21hdFsyLDJdL3N1bShjb25mX21hdFssMl0pCiAgcHJlY2kgPSAgY29uZl9tYXRbMiwyXS9zdW0oY29uZl9tYXRbMixdKQogIG5wdiA9ICAgIGNvbmZfbWF0WzEsMV0vc3VtKGNvbmZfbWF0WzEsXSkKICByZXR1cm4oYyhhY2Msc3BlY2lmLHNlbnNpdixwcmVjaSxucHYpKQp9CgojIEdldCBhdmVyYWdlIHBlcmZvcm1hbmNlCnBlcmZvcm1hbmNlIDwtIGNvbXB1dGVQZXJmb3JtYW5jZVJlc3VsdHMoc2VsZWN0ZWREZiAlPiUgc2VsZWN0KENsYXNzLCBjbHNQcmVkKSkKYWNjIDwtIHBlcmZvcm1hbmNlWzFdCnByZWMgPC0gcGVyZm9ybWFuY2VbNF0KcmVjYWxsIDwtIHBlcmZvcm1hbmNlWzNdCnNwZWMgPC0gcGVyZm9ybWFuY2VbMl0KbnB2IDwtIHBlcmZvcm1hbmNlWzVdCmYxIDwtICgyICogcmVjYWxsICogcHJlYykgLyAocmVjYWxsICsgcHJlYykKYXVjIDwtIGFzLm51bWVyaWMoeGdiX20kZXZhbHVhdGlvbl9sb2dbeGdiX20kYmVzdF9pdGVyYXRpb24sICJ0ZXN0X2F1Y19tZWFuIl0pCgpwcmludChwYXN0ZSgiQWNjdXJhY3k9Iiwgcm91bmQoYWNjLCAyKSkpCnByaW50KHBhc3RlKCJQcmVjaXNpb249Iiwgcm91bmQocHJlYywgMikpKQpwcmludChwYXN0ZSgiUmVjYWxsPSIsIHJvdW5kKHJlY2FsbCwgMikpKQpwcmludChwYXN0ZSgiU3BlY2lmaWNpdHk9Iiwgcm91bmQoc3BlYywgMikpKQpwcmludChwYXN0ZSgiTlBWPSIsIHJvdW5kKG5wdiwgMikpKQpwcmludChwYXN0ZSgiRjE9Iiwgcm91bmQoZjEsIDIpKSkKcHJpbnQocGFzdGUoIkFVQz0iLCByb3VuZChhdWMsIDIpKSkKYGBgCgpgYGB7cn0KIyBJbXBvcnRhbmNlCmJzdCA8LSB4Z2Jvb3N0KCAgIHBhcmFtcyAgICAgICAgICAgICAgID0gcGFyYW0sCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBhcy5tYXRyaXgoc2VsZWN0ZWREZiAlPiUgc2VsZWN0KC1jKENsYXNzLCBjbHNQcmVkKSkpICwKICAgICAgICAgICAgICAgICAgbGFiZWwgPSAgc2VsZWN0ZWREZiRDbGFzcywKICAgICAgICAgICAgICAgICAgbnJvdW5kcyAgICAgICAgICAgICA9IDEwMCwKICAgICAgICAgICAgICAgICAgdmVyYm9zZSAgICAgICAgICAgICA9IEYsCiAgICAgICAgICAgICAgICAgIHByZWRpY3Rpb24gICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBtYXhpbWl6ZSAgICAgICAgICAgID0gRiwgIyBDaGFuZ2UgdGhpcyB2YWx1ZSB0byBGIHdpbGwgaGVscCB0byBydW4gd2l0aCBtb3JlIGl0aW5lcmF0aW9uCiAgICAgICAgICAgICAgICAgIG5mb2xkICAgICAgICAgICAgICAgPSBuX2ZvbGRzLAogICAgICAgICAgICAgICAgICBtZXRyaWNzICAgICAgICAgICAgID0gYygiYXVjIiwgImVycm9yIiksCiAgICAgICAgICAgICAgICAgIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDUwLAogICAgICAgICAgICAgICAgICBzdHJhdGlmaWVkICAgICAgICAgICAgPSBULAogICAgICAgICAgICAgICAgICBzY2FsZV9wb3Nfd2VpZ2h0ICAgICAgPSAxKQppbXBvcnRhbmNlRGYgPC0geGdiLmltcG9ydGFuY2UoY29sbmFtZXMoc2VsZWN0ZWREZiAlPiUgc2VsZWN0KC1jKENsYXNzLCBjbHNQcmVkKSkpLCBtb2RlbCA9IGJzdCkKcHJpbnQoaW1wb3J0YW5jZURmKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHBST0MpCgpkZlJPQyA8LSBwUk9DOjpyb2MocmVzcG9uc2UgPSBpZmVsc2Uoc2VsZWN0ZWREZiRDbGFzcz09VCwgMSwgMCksCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IHJvdW5kKHhnYl9tJHByZWQpLAogICAgICAgICAgICAgICBsZXZlbHM9YygwLCAxKSwgZGlyZWN0aW9uID0gIjwiKQoKIyBpdCA9IHdoaWNoLm1heCh4Z2JfbSRldmFsdWF0aW9uX2xvZyR0ZXN0X2F1Y19tZWFuKQojIGJlc3QuaXRlciA9IHhnYl9tJGV2YWx1YXRpb25fbG9nJGl0ZXJbaXRdCiMgYmVzdC5pdGVyIAoKcGxvdChwUk9DOjpyb2MocmVzcG9uc2UgPSBpZmVsc2Uoc2VsZWN0ZWREZiRDbGFzcz09VCwgMSwgMCksCiAgICAgICAgICAgICAgIHByZWRpY3RvciA9IHJvdW5kKHhnYl9tJHByZWQpLAogICAgICAgICAgICAgICBsZXZlbHM9YygwLCAxKSwgZGlyZWN0aW9uID0gIjwiKSwgCiAgICAgbGVnYWN5LmF4ZXMgPSBUUlVFLAogICAgIG1haW49IlJPQyBDdXJ2ZSIsIAogICAgIGx3ZD0xLjUpIApgYGAKCgojIyMgUGxvdCBmZWF0dXJlIGltcG9ydGFuY2UKYGBge3J9CnlBeGlzIDwtIGxpc3QoCiAgdGl0bGUgPSAnSW1wb3J0YW5jZScsCiAgcmFuZ2U9YygwLjAsIDEuMCkKKQp4QXhpcyA8LSBsaXN0KAogIHRpdGxlID0gJycKKQoKaW1wb3J0YW5jZURmJEZlYXR1cmUgPC0gZmFjdG9yKGltcG9ydGFuY2VEZiRGZWF0dXJlLCBsZXZlbHMgPSBpbXBvcnRhbmNlRGZbb3JkZXIoLUdhaW4pLF0kRmVhdHVyZSkKZmlnX0ltcG9ydGFuY2UgPC0gcGxvdF9seShpbXBvcnRhbmNlRGYsIHggPSB+RmVhdHVyZSwgeSA9IH5HYWluLCB0eXBlID0gJ2JhcicsIG5hbWUgPSAnR2FpbicsIHdpZHRoPTYwMCkgJT4lCiAgYWRkX3RyYWNlKHkgPSB+Q292ZXIsIG5hbWUgPSAnQ292ZXInKSAlPiUgCiAgYWRkX3RyYWNlKHkgPSB+RnJlcXVlbmN5LCBuYW1lID0gJ0ZyZXF1ZW5jeScpICU+JSAKICBsYXlvdXQoeWF4aXMgPSB5QXhpcywgeGF4aXM9eEF4aXMsIGJhcm1vZGUgPSAnZ3JvdXAnLCB0aXRsZT0iRmVhdHVyZSBJbXBvcnRhbmNlIikgJT4lIAogIGNvbmZpZyguTGFzdC52YWx1ZSwgbWF0aGpheCA9ICdjZG4nKQoKaHRtbHRvb2xzOjp0YWdMaXN0KGZpZ19JbXBvcnRhbmNlKQpgYGAKCgo=